/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify %s -- --target=aarch64-linux-elf -Wno-unused-value
// RUN: cat %m | %FileCheck %s

struct foo {
  int a;
  int b;
} f;

int gA[16];

void test() {
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: asm { "; this is a comment"
  // CHECK-NEXT:    :
  // CHECK-NEXT:    :
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  __asm ("; this is a comment");

  int a, b, c;
  // CHECK: LOC 2 [[# @LINE + 7 ]]{{$}}
  // CHECK-NEXT: asm volatile { "add $0, $1, $2"
  // CHECK-NEXT:    : "=w" dassign %c 0
  // CHECK-NEXT:    : "w" (dread i32 %a),
  // CHECK-NEXT:      "w" (dread i32 %b)
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  __asm volatile ("add %[result], %[input_a], %[input_b]"
    : [result] "=w" (c)
    : [input_a] "w" (a), [input_b] "w" (b)
  );

  // CHECK: LOC 2 [[# @LINE + 7 ]]{{$}}
  // CHECK-NEXT: asm volatile { "add v0, $1, $2\n\tadd $0, v0, $2"
  // CHECK-NEXT:    : "=w" dassign %c 0
  // CHECK-NEXT:    : "w" (dread i32 %a),
  // CHECK-NEXT:      "w" (dread i32 %b)
  // CHECK-NEXT:    : "v0"
  // CHECK-NEXT:    : }
  __asm volatile (
    "add v0, %[input_a], %[input_b]\n\t"
    "add %0, v0, %2"
    : [result] "=w" (c)
    : [input_a] "w" (a), [input_b] "w" (b)
    : "v0"
  );

  mylabel:
  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: asm goto { "b $0"
  // CHECK-NEXT:    :
  // CHECK-NEXT:    :
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : @mylabel }
  asm goto ("b %0" : : : : mylabel);

  int x[4];
  // CHECK: LOC 2 [[# @LINE + 10 ]]{{$}}
  // CHECK-NEXT: asm { "add $0, $1, $2"
  // CHECK-NEXT:    : "=&w" dassign %_asmout_[[#TMPNUM:]]_0 0
  // CHECK-NEXT:    : "w" (dread i32 %a),
  // CHECK-NEXT:      "w" (dread i32 %b)
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  // CHECK-NEXT: iassign <* i32> 0 (
  // CHECK-NEXT:   array 0 a64 <* <[4] i32>> (addrof a64 %x, constval i32 1),
  // CHECK-NEXT:   dread i32 %_asmout_[[#TMPNUM]]_0)
  asm ("add %0, %1, %2"
    : "=&w" (x[1])
    : "w" (a), "w" (b));

  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: asm volatile { "ldr $0, $1\n"
  // CHECK-NEXT:    : "=r" dassign %a 0
  // CHECK-NEXT:    : "m" (addrof a64 %b)
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  asm volatile ("ldr %0, %1\n"
    : "=r" (a)
    : "m" (b));

  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: asm volatile { "ldr $0, $1\n"
  // CHECK-NEXT:    : "=r" dassign %a 0
  // CHECK-NEXT:    : "m" (addrof a64 $f 1)
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  asm volatile ("ldr %0, %1\n"
    : "=r" (a)
    : "m" (f.a));

  // CHECK: LOC 2 [[# @LINE + 6 ]]{{$}}
  // CHECK-NEXT: asm volatile { "ldr $0, $1\n"
  // CHECK-NEXT:    : "=r" dassign %a 0
  // CHECK-NEXT:    : "m" (array 0 a64 <* <[16] i32>> (addrof a64 $gA, constval i32 3))
  // CHECK-NEXT:    :
  // CHECK-NEXT:    : }
  asm volatile ("ldr %0, %1\n"
    : "=r" (a)
    : "m" (gA[3]));

  asm volatile ("" : "+m" (a), "+m" (b));
}
